package com.example.sqlutils;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.logging.Logger;
import java.util.stream.Collectors;

import static java.lang.System.out;

public class BatchUpdateData {


    static final Logger logger = Logger.getLogger(String.valueOf(BatchUpdateData.class));

    public SQlLUtil<ResultSet, Sys_dept> sQlLUtil = new SQlLUtil<>("jdbc:mysql://x/duogex?useSSL=false&characterEncoding=utf-8&rewriteBatchedStatements=true");
    public SQlLUtil<ResultSet, device> deviceSQlLUtil = new SQlLUtil<>("jdbc:mysql://x/dev-longwang-v2?useSSL=false&characterEncoding=utf-8&rewriteBatchedStatements=true");


    String getSys_dept = "select * from  sys_dept ";

    SQlLUtil.Function<ResultSet, List<device>> function1 = (rs) -> {
        List<device> list1 = new ArrayList<>();
        while (rs.next()) {
            device device = new device();
            device.setId(rs.getString("id"));
            device.setDevice_installed_address(rs.getString("device_installed_address"));
            device.setDevice_installed_code(rs.getString("device_installed_code"));
            list1.add(device);
        }
        return list1;
    };

    SQlLUtil.Function<ResultSet, List<Sys_dept>> function = (rs) -> {
        List<Sys_dept> list1 = new ArrayList<>();
        while (rs.next()) {
            list1.add(new Sys_dept(rs.getInt("dept_id"), rs.getString("name")));
        }
        return list1;
    };

    List<Sys_dept> sys_depts = sQlLUtil.runSQLList(getSys_dept, function);
    Map<Integer, String> nameMap = sys_depts.stream().collect(Collectors.toMap(Sys_dept::getId, Sys_dept::getName));


    BatchUpdateData() throws SQLException, ClassNotFoundException {
        Class.forName("com.mysql.cj.jdbc.Driver");

    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    static class device {
        String id;
        String device_installed_address;
        String device_installed_code;

        Integer count;

        public device self() {
            return this;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            device device = (device) o;
            return Objects.equals(id, device.id);
        }

        @Override
        public int hashCode() {
            return Objects.hash(id);
        }
    }

    @Data
    @AllArgsConstructor
    static class Sys_dept {
        int id;
        String name;

        public Sys_dept self() {
            return this;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Sys_dept sys_dept = (Sys_dept) o;
            return id == sys_dept.id;
        }

        @Override
        public int hashCode() {
            return Objects.hash(id);
        }
    }


    public void main(Integer start, Integer end) throws SQLException {
        logger.info("线程名称：" + Thread.currentThread().getName());
        String sql = "select id,device_installed_address,device_installed_code from device  limit " + start + " , " + end;
        List<device> list = deviceSQlLUtil.runSQLList(sql, function1);

        String update = "update device SET device_installed_address = ?  where id = ? ";

        Long startTime = System.currentTimeMillis();
        out.println("更新成功： " + deviceSQlLUtil.updateSQL(update, list, (ps, deviceList) -> {
            deviceList.forEach(
                    item -> {
                        String[] codes = item.getDevice_installed_code().split(",");
                        StringBuilder where = new StringBuilder();
                        for (String code : codes) {
                            where.append(nameMap.get(Integer.parseInt(code))).append("/");
                        }
                        where.delete(where.length() - 1, where.length());
                        try {
                            ps.setString(1, where.toString());
                            ps.setString(2, item.getId());
                            ps.addBatch();
                        } catch (SQLException e) {
                            throw new RuntimeException(e);
                        }
                    }
            );
        }));
        logger.info("耗时: " + (System.currentTimeMillis() - startTime));
    }

    public void close() throws SQLException {
        sQlLUtil.close();
        deviceSQlLUtil.close();
    }

    @Data
    @AllArgsConstructor
    static class Num {
        int start;
        int end;

    }

    public static void main(String[] args) throws SQLException {
        Long startTime = System.currentTimeMillis();
        BatchUpdateData batchUpdateData = null;
        try {
            batchUpdateData = new BatchUpdateData();
            String sql = "select count(*) from device limit 1000";
            Integer count = batchUpdateData.deviceSQlLUtil.runSQL(sql, item -> {
                device device = new device();
                if (item.next()) {
                    device.setCount(item.getInt(1));
                }
                return device;
            }).getCount();
//            Integer count = 22000;
            int NUMBER = 10000;
            int sum = 0;

//            ExecutorService cachedThreadPool = Executors.newFixedThreadPool(2);
//            ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(2);

            List<Num> list = Collections.synchronizedList(new ArrayList<>());

            n:
            while (true) {
                for (int i = 1; i <= 10; i++) {
                    if (count <= sum) {
                        break n;
                    }
                    int finalSum = sum;
                    int end = finalSum + NUMBER;
                    try {
                        batchUpdateData.main(finalSum, end);
                    } catch (SQLException e) {
                        list.add(new Num(finalSum, end));
                        throw new RuntimeException(e);
                    }
//                    Runnable runnable = () -> {
//                        int end = finalSum + NUMBER;
//                        try {
//                            batchUpdateData.main(finalSum, end);
//                        } catch (SQLException e) {
//                            list.add(new Num(finalSum, end));
//                            throw new RuntimeException(e);
//                        }
//                    };
//                    cachedThreadPool.execute(runnable);
                    sum += NUMBER;
                    logger.info("开始 " + sum);
                }
            }
            // 重试机制
//        threadPool.schedule(() -> {
//            if (list.size() > 0) {
//                int finalSum = list.get(0).getStart();
//                int end = list.get(0).getEnd();
//                list.remove(0);
//                try {
//                    batchUpdateData.main(finalSum, end);
//                } catch (SQLException e) {
//                    list.add(new Num(finalSum, end));
//                    throw new RuntimeException(e);
//                }
//            }
//        }, 3, TimeUnit.SECONDS); // 3s 之后执行
//            cachedThreadPool.awaitTermination(1000, TimeUnit.SECONDS);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            batchUpdateData.close();
        }

        logger.info("耗时: " + (System.currentTimeMillis() - startTime));
    }
}